#!/usr/bin/python3
# -*- coding: utf-8 -*-
 
import sys
from PyQt5.QtWidgets import QApplication, QWidget,QMainWindow,QFileDialog
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QObject, QTimer

import midiPlay2 as midiPlay
import _thread
import time
from PyQt5 import QtCore, QtGui, QtWidgets
import midi_play_list

T_TO_HEIGHT = 1000
BLOCK_MAX = 8
BLOCK_DEFAUTLY_Y = -2000


MAX_NOTE = 88
NOTE_OFFSET = 21

WHITE_BLOCK_X = midiPlay.PIANO_KEYBOARD_WHITE_SIZE[0] / 1.5
BLACK_BLOCK_X =  midiPlay.PIANO_KEYBOARD_BLACK_SIZE[0] / 1.5

NOTE_ON_DISTANCE = 1400

# music_data = midi_play_list.get_play_list("../../source/midi/myMidi/popularMusic/陈奕迅 十年 .mid")
music_data = midi_play_list.get_play_list("../../source/midi/myMidi/pianoClassic/野蜂飞舞.mid")

# print(music_data)
test_data_note = []

for i in range(MAX_NOTE):
    test_data_note.append([])

for i in range(len(music_data)):
    idx = music_data[i][0] - NOTE_OFFSET
    if idx < MAX_NOTE:
        test_data_note[idx].append(music_data[i])

# 21 ~ 108
class piano_info():
    def __init__(self, note_info):
        self.note_info = note_info
        self.block_info = [0, 0]
        self.block_note = [0] * BLOCK_MAX

        self.startTime = [0] * BLOCK_MAX
        self.startPos = [0] * BLOCK_MAX
        self.doneIdx = 0


import pygame.midi as pm
 
pm.init() # init midi player
player = pm.Output(0)
player.set_instrument(0)
note_sta = [0] * 128
def play_note(pitch=60, sta = 1, velocity=127):
    global note_sta
    if sta and (not note_sta[pitch]):    
        player.note_on(pitch, velocity)
        note_sta[pitch] = 1
    elif (not sta) and note_sta[pitch]:
        player.note_off(pitch, velocity)
        note_sta[pitch] = 0


class myWindow(QMainWindow, midiPlay.Ui_MainWindow):
    def __init__(self):
        super().__init__()
        super().setupUi(self)

        self.midi_play_idx = 0
        self.dynamicBlocks = []

        whiteIdx = 0
        blackIdx = 0

        for j in range(BLOCK_MAX):
            for i in range(MAX_NOTE):
                if ((i + 9) % 12) in [1,3,6,8,10]:
                    self.createBlackBlock(0, 100, name = "")
                    x = self.pianoKey[i].x()
                    self.dynamicBlocks[-1].move(x, BLOCK_DEFAUTLY_Y)
                    blackIdx += 1
                else:
                    self.createWhiteBlock(0, 100, name = str((whiteIdx + 5) % 7 + 1))
                    x = self.pianoKey[i].x()
                    self.dynamicBlocks[-1].move(x, BLOCK_DEFAUTLY_Y)
                    whiteIdx += 1

        self.test_ = None
        self.pianoData = []
        for i in range(MAX_NOTE):
            self.pianoData.append(piano_info(test_data_note[i]))

        self.Timer = QTimer(self)
        self.Timer.timeout.connect(self.updateWork)
        self.startTime = time.time()
        self.currentTime = self.startTime
        self.Timer.start(10)

    def play_midi(self):
        for i in range(self.midi_play_idx, len(music_data)):
            if music_data[i][2] <= self.currentTime:
                if music_data[i][1]:
                    play_note(music_data[i][0], 1, music_data[i][3])
                else:
                    play_note(music_data[i][0], 0, music_data[i][3])
                self.midi_play_idx += 1
            else:
                break


    def updateWork(self):
        self.currentTime = (time.time() - self.startTime)

        self.play_midi()

        for k in range(MAX_NOTE):
            self.test_ = self.pianoData[k]
            while self.test_.block_info[1] - self.test_.block_info[0] < BLOCK_MAX:
                if self.test_.doneIdx < len(self.test_.note_info):
                    t_h = (self.test_.note_info[self.test_.doneIdx + 1][2] -  self.test_.note_info[self.test_.doneIdx][2]) * T_TO_HEIGHT
                    y =  NOTE_ON_DISTANCE  - (self.test_.note_info[self.test_.doneIdx][2] - self.currentTime) * T_TO_HEIGHT - t_h
                    idx = ((self.test_.block_info[1] % BLOCK_MAX) * MAX_NOTE) + k
                    velocity = self.test_.note_info[self.test_.doneIdx][3]
                    self.test_.block_note[(self.test_.block_info[1] % BLOCK_MAX)] = self.test_.note_info[self.test_.doneIdx]
                    self.test_.startPos[(self.test_.block_info[1] % BLOCK_MAX)] = y
                    self.blockHome(idx, y, t_h, k, velocity)
                    self.test_.startTime[self.test_.block_info[1] % BLOCK_MAX] = self.currentTime 
                    self.test_.block_info[1] += 1

                    self.test_.doneIdx += 2
                else:
                    break


            for i in range(self.test_.block_info[1] - self.test_.block_info[0]):
                idx1 = (self.test_.block_info[0] + i) % BLOCK_MAX
                idx = idx1 * MAX_NOTE + k
                x =  self.dynamicBlocks[idx].x()
                y =  self.test_.startPos[idx1]+ (self.currentTime - self.test_.startTime[idx1]) * T_TO_HEIGHT
                h = self.dynamicBlocks[idx].height()

                if y < -h:
                    break
                self.dynamicBlocks[idx].move(x, y)


            for i in range(self.test_.block_info[1] - self.test_.block_info[0]):
                idx1 = (self.test_.block_info[0] + i) % BLOCK_MAX
                idx = idx1 * MAX_NOTE + k
                x =  self.dynamicBlocks[idx].x()
                h =  self.dynamicBlocks[idx].height()
                y =  self.dynamicBlocks[idx].y()

                if y > NOTE_ON_DISTANCE:
                    self.test_.block_info[0] += 1
                    self.blockHome(idx, BLOCK_DEFAUTLY_Y, k, h)
                    if ((k + 9)% 12) in [1,3,6,8,10]:
                        self.pianoKey[k].setStyleSheet("background-color: rgb(0, 0, 0);")
                    else:
                        if k == 39:
                            self.pianoKey[k].setStyleSheet("background-color: rgb(200, 200, 200);")
                        else:
                            self.pianoKey[k].setStyleSheet("background-color: rgb(255, 255, 255);")
                    # play_note(self.test_.block_note[idx1][0], 0, self.test_.block_note[idx1][3])


                elif y + h >= NOTE_ON_DISTANCE:
                    if ((k + 9)% 12) in [1,3,6,8,10]:
                        self.pianoKey[k].setStyleSheet("background-color: rgb(200, 200, 0);")
                    else:
                        self.pianoKey[k].setStyleSheet("background-color: rgb(0, 200, 0);")

                    # play_note(self.test_.block_note[idx1][0], 1, self.test_.block_note[idx1][3])
                


    def createWhiteBlock(self, x, h, spd = 100, name = ""):
        pBtn = QtWidgets.QPushButton(self.frame)
        pBtn.setGeometry(QtCore.QRect(x, 0, WHITE_BLOCK_X, h))
        pBtn.setStyleSheet("background-color: rgb(0, 255, 0);")
        pBtn.setText(name)
        pBtn.setObjectName("block" + name)

        self.dynamicBlocks.append(pBtn)

    def createBlackBlock(self, x, h, spd = 100, name = ""):
        pBtn = QtWidgets.QPushButton(self.frame)
        pBtn.setGeometry(QtCore.QRect(x, 0, BLACK_BLOCK_X, h))
        pBtn.setStyleSheet("background-color: rgb(255, 255, 0);")
        pBtn.setText(name)
        pBtn.setObjectName("block" + name)

        self.dynamicBlocks.append(pBtn)

    def blockHome(self, idx, y, h, k, v = 127):
        x = self.dynamicBlocks[idx].x()
        width = self.dynamicBlocks[idx].width()

        self.dynamicBlocks[idx].resize(width, h)
        self.dynamicBlocks[idx].move(x, y)
        self.dynamicBlocks[idx].lower()
        if ((k + 9) % 12) in [1,3,6,8,10]:
            self.dynamicBlocks[idx].setStyleSheet("background-color: rgb({}, {}, 0);".format(v*2, v*2))
        else:
            self.dynamicBlocks[idx].setStyleSheet("background-color: rgb(0, {}, 0);".format(v*2))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = myWindow()
    ex.show()
    sys.exit(app.exec_()) 

